﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace NcfDB.parsing
{
    public class calculate
    {
        public static bool calWhere(List<Word> source)
        {
            if (source.Count < 1) return true;
            bool target = true;
            double d;
            Stack<string> opr = new Stack<string>();//算符栈
            List<string> rsl = new List<string>();//结果表
            Stack<string> rs = new Stack<string>();//结果栈
            opr.Push("#");
            rsl.Add("#");
            //转后缀表达式
            for (int i = 0; i < source.Count; i++)
            {
                //比对的值直接放入后缀表达式
                if (source[i].type == WORD_TYPE_ENUM.VALUE || source[i].type == WORD_TYPE_ENUM.BOOL)
                {
                    rsl.Add(source[i].value);
                }
                else if (source[i].name == ")") //遇到右括号将算符栈中的数据弹出直到左括号
                {
                    while (opr.Peek() != "(")
                    {
                        rsl.Add(opr.Pop());
                    }
                    opr.Pop();//弹出左括号
                }
                else if (source[i].name == "BETWEEN")//遇到between时
                {
                    opr.Push(source[i].name);//压入between
                    i++;
                    rsl.Add(source[i].value);//输出第一个参数
                    i = i + 2;                   //跳过and
                    rsl.Add(source[i].value);//输出第二个参数
                    continue;
                }
                else if (getLevel(opr.Peek()) < getLevel(source[i].name))
                {
                    opr.Push(source[i].name);//新来算符优先级高于栈顶，压入新算符

                }
                else if (getLevel(opr.Peek()) >= getLevel(source[i].name)) //新来算符优先级低于栈顶，
                {
                    while (getLevel(opr.Peek()) >= getLevel(source[i].name)) //弹出算符直到栈顶低于当前算符
                    {
                        rsl.Add(opr.Pop());
                    }
                    opr.Push(source[i].name);//压入新算符
                }

            }
            while (opr.Peek() != "#")
            {
                rsl.Add(opr.Pop());//弹出剩余算符
            }
            for (int i = 1; i < rsl.Count; i++)
            {
                if (rsl[i] == "=")
                {
                    if (double.TryParse(rsl[i], out  d))
                    {
                        rs.Push(Eql(double.Parse(rs.Pop()), double.Parse(rs.Pop())).ToString());
                    }
                    else
                    {
                        rs.Push(Eql(rs.Pop(), rs.Pop()).ToString());
                    }

                }
                else if (rsl[i] == "<")
                {

                    rs.Push(Les(double.Parse(rs.Pop()), double.Parse(rs.Pop())).ToString());


                }
                else if (rsl[i] == ">")
                {

                    rs.Push(Gtr(double.Parse(rs.Pop()), double.Parse(rs.Pop())).ToString());


                }
                else if (rsl[i] == ">=")
                {

                    rs.Push(Geq(double.Parse(rs.Pop()), double.Parse(rs.Pop())).ToString());


                }
                else if (rsl[i] == "<=")
                {

                    rs.Push(Leq(double.Parse(rs.Pop()), double.Parse(rs.Pop())).ToString());


                }
                else if (rsl[i] == "BETWEEN")
                {

                    rs.Push(Between(double.Parse(rs.Pop()), double.Parse(rs.Pop()), double.Parse(rs.Pop())).ToString());


                }
                else if (rsl[i] == "AND")
                {

                    rs.Push(And(bool.Parse(rs.Pop()), bool.Parse(rs.Pop())).ToString());


                }
                else if (rsl[i] == "OR")
                {

                    rs.Push(Or(bool.Parse(rs.Pop()), bool.Parse(rs.Pop())).ToString());


                }
                else if (rsl[i] == "LIKE")
                {

                    rs.Push(Like(rs.Pop(), rs.Pop()).ToString());


                }
                else rs.Push(rsl[i]);
            }
            target = bool.Parse(rs.Pop());






            return target;
        }
        public static int getLevel(string source)
        {
            switch (source)
            {
                case "AND": return 4;
                case "OR": return 3;
                case "#": return 1;
                case ">":
                case ">=":
                case "<=":
                case "<":
                case "LIKE":
                case "BETWEEN":
                case "=": return 7;
                case "(": return 2;
                case ")": return 9;
            }
            return -1;
        }
        public static bool And(bool source1, bool source2)
        {
            if (source1 == false || source2 == false) return false;
            return true;
        }
        public static bool Or(bool source1, bool source2)
        {
            if (source1 == true || source2 == true) return true;
            return false;
        }
        public static bool Eql(string source1, string source2)
        {
            if (source1 == source2) return true;
            return false;
        }
        public static bool Eql(double source1, double source2)
        {
            if (source1 == source2) return true;
            return false;
        }

        public static bool Gtr(double source2, double source1)
        {
            if (source1 > source2) return true;
            return false;
        }

        public static bool Les(double source2, double source1)
        {
            if (source1 < source2) return true;
            return false;
        }
        public static bool Leq(double source2, double source1)
        {
            if (source1 <= source2) return true;
            return false;
        }
        public static bool Geq(double source2, double source1)
        {
            if (source1 >= source2) return true;
            return false;
        }
        public static bool Like(string source2, string source1)
        {
            string[] wild = new string[] { };
            wild = source2.Split(new char[] { '%' });
            int searchlocation = 0;
            for (int i = 0; i < wild.Length; i++)
            {
                searchlocation = source1.IndexOf(wild[i], searchlocation);
                if (i == 0 && searchlocation != 0) return false;
                if (searchlocation < 0) return false;
            }
            return true;
        }
        public static bool Between(double source3, double source2, double source1)
        {
            if (source1 >= source2 && source1 >= source3) return false;
            if (source1 <= source2 && source1 <= source3) return false;
            return true;
        }

        
    }
}
